home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ARASAN_S.ZIP
/
NOTATION.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-07
|
5KB
|
240 lines
// Copyright 1994 by Jon Dart. All Rights Reserved.
#include "notation.h"
#include "board.h"
#include "emove.h"
#include "bearing.h"
#include <ctype.h>
#include <string.h>
// This module handles I/O of standard algebraic notation (SAN).
// Note that we can't put this into the Move class, because a
// move doesn't contain enough info by itself to produce SAN -
// we need the board position, too.
void Notation::
Image(const Board & b, const Move & m, char *image)
{
ExtendedMove emove(b, m);
Piece p = emove.PieceMoved();
if (emove.Special() == ExtendedMove::KCastle)
{
strcpy(image, "O-O");
return;
}
else if (emove.Special() == ExtendedMove::QCastle)
{
strcpy(image, "O-O-O");
return;
}
int k = 0;
if (p.Type() == Piece::Pawn)
{
if (emove.Capture().IsEmpty())
{
image[k] = m.DestSquare().FileImage();
k++;
image[k] = m.DestSquare().RankImage();
k++;
}
else
{
image[k] = m.StartSquare().FileImage();
k++;
image[k] = 'x';
k++;
image[k] = m.DestSquare().FileImage();
k++;
image[k] = m.DestSquare().RankImage();
k++;
}
if (emove.Special() == ExtendedMove::Promotion)
{
image[k] = '=';
k++;
image[k] = Piece::Image(m.PromoteTo());
k++;
}
image[k] = '\0';
return;
}
else
{
image[k] = Piece::Image(p.Type());
k++;
Square squares[Bearing::MaxBearSq];
unsigned n = Bearing::Attack(b, m.DestSquare(), b.Side(), squares);
int dups = 0;
int files[8];
int ranks[8];
if (n > 1)
{
for (unsigned i = 0; i < n; i++)
{
if (b[squares[i]].Type() == p.Type())
{
files[dups] = squares[i].File();
ranks[dups] = squares[i].Rank(White);
++dups;
}
}
}
if (dups > 1)
{
// need to disambiguate move. There are some rare cases
// (e.g. a player with 3 rooks) for which this code might
// not be sufficient.
if (files[0] != files[1])
{
image[k] = m.StartSquare().FileImage();
k++;
}
else
{
image[k] = m.StartSquare().RankImage();
k++;
}
}
if (!emove.Capture().IsEmpty())
{
image[k] = 'x';
k++;
}
image[k] = m.DestSquare().FileImage();
k++;
image[k] = m.DestSquare().RankImage();
k++;
image[k] = '\0';
}
}
Move Notation::
Value(const Board & board,
const ColorType side, char *image)
{
char *p;
int rank = 0;
int file = 0;
Piece::PieceType piece;
Piece:: PieceType promotion = Piece::Invalid;
Square dest, start;
Boolean capture = False;
for (p = image; isspace(*p); ++p);
if (!isalpha(*p))
return Move::NullMove();
if (toupper(*p) == 'O')
{
// castling, we presume
char tmp[10];
strncpy(tmp, p, 9);
for (char *q = tmp; *q; q++)
*q = toupper(*q);
return Move::Value(tmp, side);
}
if (isupper(*p))
{
piece = Piece::Value(*p);
++p;
}
else
{
piece = Piece::Pawn;
file = *p - 'a' + 1;
if (*(p + 1) == 'x')
{
capture = True;
++p;
}
}
if (piece == Piece::Invalid)
return Move::NullMove();
if (piece != Piece::Pawn)
{
// look for disambiguating rank or file, e.g. 'b' in "Nbd7".
if (isdigit(*p))
{
rank = *p - '0';
++p;
}
else if (*p != 'x' && isalpha(*p) && isalpha(*(p + 1)))
{
file = *p - 'a' + 1;
++p;
}
}
if (*p == 'x')
{
capture = True;
++p;
}
// remainder of move should be a square identifier, e.g. "g7"
dest = Square::Value(p);
if (dest == Square::Invalid())
return Move::NullMove();
p += 2;
if (*p == '=')
{
promotion = Piece::Value(*(p + 1));
if (piece != Piece:: Pawn || promotion == Piece::Invalid)
return Move::NullMove();
}
// ok, now we need to figure out where the start square is.
int dups = 0;
if (capture && piece == Piece::Pawn && board[dest].IsEmpty() &&
dest.Rank(board.Side()) != 8)
{
// en passant capture, special case
int start_rank = (board.Side() == White) ?
dest.Rank(White) - 1 :
dest.Rank(White) + 1;
start = Square(file, start_rank, White);
dups = 1;
}
else
{
static Square squares[36];
int n = Bearing::Attack(board, dest, side, squares);
for (int i = 0; i < n; i++)
{
Square maybe(squares[i]);
if (board[maybe].Type() == piece)
{
if (file && maybe.File() != file)
continue;
else if (rank && maybe.Rank(White) != rank)
continue;
else
{
// Possible move to this square. Make sure it is legal.
Board board_copy(board);
ExtendedMove emove(board_copy,maybe,dest,promotion);
board_copy.MakeMove(emove);
if (board_copy.num_attacks(
board_copy.KingPos(board_copy.OppositeSide()),
board_copy.Side()) == 0)
{
++dups;
start = maybe;
}
}
}
}
}
if (dups == 1)
return Move(start, dest, promotion);
else // ambiguous move
return Move::NullMove();
}